<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>系统监控 - MineContext</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <style>
        body {
            padding-top: 56px;
        }
        .navbar {
            background-color: #212529 !important;
        }
        .metric-card {
            transition: all 0.3s ease;
            height: 100%;
        }
        .metric-card .card-body {
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            height: 100%;
        }
        .metric-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
        }
        .chart-container {
            position: relative;
            height: 350px;
            margin: 20px 0;
        }
        .refresh-btn {
            position: fixed;
            top: 70px;
            right: 20px;
            z-index: 1000;
        }
        .loading {
            display: none;
        }
        .loading.active {
            display: inline-block;
        }
        .metric-value {
            font-size: 2.5rem;
            font-weight: bold;
        }
        .metric-label {
            font-size: 0.9rem;
            color: #6c757d;
        }
        .time-range-selector {
            margin-bottom: 10px;
        }
    </style>
</head>
<body class="bg-light">
    <!-- 顶部导航栏 -->
    <nav class="navbar navbar-dark bg-dark fixed-top">
        <div class="container-fluid">
            <div class="d-flex align-items-center">
                <a class="navbar-brand" href="/">OpenContext - 系统监控</a>
                <a href="/" class="btn btn-outline-light btn-sm ms-3">回到 home 页</a>
            </div>
            <div class="d-flex">
                <a href="/" class="btn btn-outline-light btn-sm me-2">返回主页</a>
            </div>
        </div>
    </nav>

    <!-- 主内容区域 -->
    <div class="container-fluid px-4">
        <!-- 刷新按钮 -->
        <button class="btn btn-primary refresh-btn" onclick="refreshAllData()">
            <span class="loading spinner-border spinner-border-sm" role="status"></span>
            刷新数据
        </button>

        <!-- 页面标题 -->
        <div class="row mt-3">
            <div class="col-12">
                <h1 class="text-center mb-4">OpenContext 系统监控</h1>
                <div class="alert alert-info">
                    <strong>系统运行时间:</strong> <span id="uptime">加载中...</span> |
                    <strong>最后更新:</strong> <span id="lastUpdate">加载中...</span>
                </div>
            </div>
        </div>

        <!-- 核心指标卡片 - 2个（Token消耗 + Context统计，带时间范围选择） -->
        <div class="row mb-4">
            <!-- Token 消耗统计 -->
            <div class="col-md-6">
                <div class="card metric-card border-primary">
                    <div class="card-body">
                        <div class="d-flex justify-content-between align-items-center mb-3">
                            <h5 class="card-title text-primary mb-0">Token 消耗统计</h5>
                            <div class="btn-group time-range-selector" role="group">
                                <input type="radio" class="btn-check" name="tokenTimeRange" id="token24h" value="24" checked>
                                <label class="btn btn-outline-primary btn-sm" for="token24h">24小时</label>

                                <input type="radio" class="btn-check" name="tokenTimeRange" id="token7d" value="168">
                                <label class="btn btn-outline-primary btn-sm" for="token7d">7天</label>
                            </div>
                        </div>
                        <div class="metric-value text-center text-primary" id="totalTokens">-</div>
                        <small class="metric-label d-block text-center">总消耗 Token</small>
                    </div>
                </div>
            </div>

            <!-- Context 统计 -->
            <div class="col-md-6">
                <div class="card metric-card border-success">
                    <div class="card-body">
                        <div class="d-flex justify-content-between align-items-center mb-3">
                            <h5 class="card-title text-success mb-0">Context 统计</h5>
                            <div class="btn-group time-range-selector" role="group">
                                <input type="radio" class="btn-check" name="contextTimeRange" id="context24h" value="24" checked>
                                <label class="btn btn-outline-success btn-sm" for="context24h">近24h新增</label>

                                <input type="radio" class="btn-check" name="contextTimeRange" id="contextAll" value="all">
                                <label class="btn btn-outline-success btn-sm" for="contextAll">全部记录</label>
                            </div>
                        </div>
                        <div class="metric-value text-center text-success" id="totalContexts">-</div>
                        <small class="metric-label d-block text-center" id="contextLabel">24小时内新增</small>
                    </div>
                </div>
            </div>
        </div>

        <!-- 图表区域 - 2个 -->
        <div class="row mb-4">
            <!-- 环节耗时分布 -->
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h5>环节耗时分布</h5>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="stageTimingChart"></canvas>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 模型Token使用分布 -->
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h5>模型Token使用分布</h5>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="tokenUsageChart"></canvas>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Context 类型分布图表 -->
        <div class="row mb-4">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                        <h5 id="contextChartTitle">Context 类型分布（24小时新增）</h5>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="contextStatsChart"></canvas>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 数据处理监控 -->
        <div class="row mb-4">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                        <h5>数据处理监控（24小时）</h5>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="dataProcessingTrendChart"></canvas>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 处理错误日志 -->
        <div class="row mb-5">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                        <h5>处理错误日志（最近1天，最多20条）</h5>
                    </div>
                    <div class="card-body">
                        <div id="processingErrorsChart">加载中...</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        let charts = {};
        let currentTokenTimeRange = 24; // Default 24 hours
        let currentContextTimeRange = '24'; // Default 24 hours, 'all' for all records

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            loadAllData();

            // 监听 Token 时间范围切换
            document.querySelectorAll('input[name="tokenTimeRange"]').forEach(radio => {
                radio.addEventListener('change', function() {
                    currentTokenTimeRange = parseInt(this.value);
                    loadTokenData();
                });
            });

            // 监听 Context 时间范围切换
            document.querySelectorAll('input[name="contextTimeRange"]').forEach(radio => {
                radio.addEventListener('change', function() {
                    currentContextTimeRange = this.value;
                    loadContextData();
                });
            });
        });

        async function refreshAllData() {
            const refreshBtn = document.querySelector('.refresh-btn');
            const loading = refreshBtn.querySelector('.loading');
            loading.classList.add('active');
            refreshBtn.disabled = true;

            try {
                await loadAllData();
            } finally {
                loading.classList.remove('active');
                refreshBtn.disabled = false;
            }
        }

        async function loadAllData() {
            try {
                // 获取系统概览
                const overview = await fetchData('/api/monitoring/overview');
                updateOverview(overview.data);

                // 获取Token数据
                await loadTokenData();

                // 获取Context数据
                await loadContextData();

                // 获取环节耗时
                const stageTiming = await fetchData('/api/monitoring/stage-timing');
                updateStageTimingChart(stageTiming.data);

                // 获取数据统计（用于 Context 统计）
                const dataStats = await fetchData('/api/monitoring/data-stats?hours=24');
                // Context 统计在 loadContextData 中处理

                // 获取数据处理趋势（用于趋势图）
                const dataTrend = await fetchData('/api/monitoring/data-stats-trend?hours=24');
                updateDataProcessingTrend(dataTrend.data);

                // 获取处理错误（最近1天，最多20条）
                const processingErrors = await fetchData('/api/monitoring/processing-errors?hours=24&top=20');
                updateProcessingErrorsChart(processingErrors.data);

            } catch (error) {
                console.error('Failed to load monitoring data:', error);
                showError('加载监控数据失败: ' + error.message);
            }
        }

        async function loadTokenData() {
            try {
                const tokenUsage = await fetchData(`/api/monitoring/token-usage?hours=${currentTokenTimeRange}`);
                updateTokenDisplay(tokenUsage.data);
                updateTokenUsageChart(tokenUsage.data);
            } catch (error) {
                console.error('Failed to load token data:', error);
            }
        }

        async function loadContextData() {
            try {
                let url, chartTitle, label;

                if (currentContextTimeRange === 'all') {
                    // 获取全部记录
                    const overview = await fetchData('/api/monitoring/overview');
                    const contextTypes = overview.data.context_types || {};
                    const total = Object.values(contextTypes).reduce((sum, count) => sum + count, 0);

                    updateContextDisplay(total, '全部记录');
                    updateContextChart(contextTypes, 'Context 类型分布（全部记录）');
                } else {
                    // 获取24小时新增
                    const dataStats = await fetchData('/api/monitoring/data-stats?hours=24');
                    const contextTypes = dataStats.data.by_context_type || {};
                    const total = Object.values(contextTypes).reduce((sum, count) => sum + count, 0);

                    updateContextDisplay(total, '24小时内新增');
                    updateContextChart(contextTypes, 'Context 类型分布（24小时新增）');
                }
            } catch (error) {
                console.error('Failed to load context data:', error);
            }
        }

        async function fetchData(url) {
            const response = await fetch(url);
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            return await response.json();
        }

        function updateOverview(data) {
            document.getElementById('uptime').textContent = data.uptime_formatted || '未知';
            document.getElementById('lastUpdate').textContent = new Date(data.last_updated).toLocaleString();
        }

        function updateTokenDisplay(data) {
            document.getElementById('totalTokens').textContent = data.total_tokens?.toLocaleString() || '0';
        }

        function updateContextDisplay(total, label) {
            document.getElementById('totalContexts').textContent = total.toLocaleString();
            document.getElementById('contextLabel').textContent = label;
        }

        function updateContextChart(contextTypes, chartTitle) {
            const ctx = document.getElementById('contextStatsChart').getContext('2d');
            const types = Object.keys(contextTypes);
            const counts = Object.values(contextTypes);

            // 更新图表标题
            document.getElementById('contextChartTitle').textContent = chartTitle;

            if (charts.contextStats) {
                charts.contextStats.destroy();
            }

            charts.contextStats = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: types,
                    datasets: [{
                        label: '数量',
                        data: counts,
                        backgroundColor: '#FF6384'
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: true,
                            ticks: {
                                stepSize: 1
                            }
                        }
                    }
                }
            });
        }

        function updateStageTimingChart(data) {
            const ctx = document.getElementById('stageTimingChart').getContext('2d');
            const stages = Object.keys(data.by_stage || {});
            const avgDurations = stages.map(stage => data.by_stage[stage].avg_duration);

            if (charts.stageTiming) {
                charts.stageTiming.destroy();
            }

            charts.stageTiming = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: stages,
                    datasets: [{
                        label: '平均耗时 (ms)',
                        data: avgDurations,
                        backgroundColor: '#36A2EB'
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: true
                        }
                    }
                }
            });
        }

        function updateTokenUsageChart(data) {
            const ctx = document.getElementById('tokenUsageChart').getContext('2d');
            const models = Object.keys(data.by_model || {});
            const tokenCounts = models.map(model => data.by_model[model].total_tokens);

            if (charts.tokenUsage) {
                charts.tokenUsage.destroy();
            }

            charts.tokenUsage = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: models,
                    datasets: [{
                        label: 'Token消耗',
                        data: tokenCounts,
                        backgroundColor: '#4BC0C0'
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: true
                        }
                    }
                }
            });
        }

        function updateDataStats(data) {
            // 只处理数据处理量趋势图
            updateDataProcessingTrend(data);
        }

        function updateDataProcessingTrend(data) {
            const ctx = document.getElementById('dataProcessingTrendChart').getContext('2d');

            // 使用真实的趋势数据
            const trend = data.trend || { screenshot: [], document: [], context: [] };
            const timestamps = data.timestamps || [];

            // 生成过去24小时的完整时间序列（每小时一个点）
            const now = new Date();
            const labels = [];
            const timeMap = {};

            // 创建完整的24小时时间序列
            for (let i = 23; i >= 0; i--) {
                const time = new Date(now.getTime() - i * 60 * 60 * 1000);
                // 使用与后端一致的格式：YYYY-MM-DD HH:00:00（空格，不是T）
                const year = time.getFullYear();
                const month = String(time.getMonth() + 1).padStart(2, '0');
                const day = String(time.getDate()).padStart(2, '0');
                const hour = String(time.getHours()).padStart(2, '0');
                const timeStr = `${year}-${month}-${day} ${hour}:00:00`;
                const label = time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
                labels.push(label);
                timeMap[timeStr] = labels.length - 1;
            }

            // 初始化数据数组（全部为0）
            const screenshotData = new Array(labels.length).fill(0);
            const documentData = new Array(labels.length).fill(0);
            const contextData = new Array(labels.length).fill(0);

            // 填充真实数据
            if (trend.screenshot) {
                trend.screenshot.forEach(item => {
                    const idx = timeMap[item.timestamp];
                    if (idx !== undefined) {
                        screenshotData[idx] = item.count;
                    }
                });
            }

            if (trend.document) {
                trend.document.forEach(item => {
                    const idx = timeMap[item.timestamp];
                    if (idx !== undefined) {
                        documentData[idx] = item.count;
                    }
                });
            }

            if (trend.context) {
                trend.context.forEach(item => {
                    const idx = timeMap[item.timestamp];
                    if (idx !== undefined) {
                        contextData[idx] = item.count;
                    }
                });
            }

            if (charts.dataProcessingTrend) {
                charts.dataProcessingTrend.destroy();
            }

            charts.dataProcessingTrend = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: labels,
                    datasets: [
                        {
                            label: '图片/截图',
                            data: screenshotData,
                            borderColor: '#36A2EB',
                            backgroundColor: 'rgba(54, 162, 235, 0.1)',
                            tension: 0.4,
                            fill: true
                        },
                        {
                            label: '文档文件',
                            data: documentData,
                            borderColor: '#FF9F40',
                            backgroundColor: 'rgba(255, 159, 64, 0.1)',
                            tension: 0.4,
                            fill: true
                        },
                        {
                            label: '处理完成的Context',
                            data: contextData,
                            borderColor: '#9966FF',
                            backgroundColor: 'rgba(153, 102, 255, 0.1)',
                            tension: 0.4,
                            fill: true
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: true,
                            ticks: {
                                stepSize: 1
                            }
                        }
                    },
                    plugins: {
                        legend: {
                            position: 'top'
                        }
                    }
                }
            });
        }

        function updateProcessingErrorsChart(data) {
            let errorHtml = '<div class="table-responsive"><table class="table table-striped table-hover"><thead><tr><th width="20%">时间</th><th width="15%">处理器</th><th width="50%">错误信息</th><th width="15%">上下文数</th></tr></thead><tbody>';

            if (data.errors && data.errors.length > 0) {
                for (const error of data.errors) {
                    const timestamp = new Date(error.timestamp).toLocaleString();
                    const processorName = error.processor_name || '-';
                    errorHtml += `<tr>
                        <td><small>${timestamp}</small></td>
                        <td><small>${processorName}</small></td>
                        <td><small class="text-break">${error.error_message}</small></td>
                        <td class="text-center">${error.context_count}</td>
                    </tr>`;
                }
            } else {
                errorHtml += '<tr><td colspan="4" class="text-center text-success"><i class="bi bi-check-circle"></i> 近1天内无处理错误</td></tr>';
            }

            errorHtml += '</tbody></table></div>';
            if (data.total_errors > 0) {
                errorHtml += `<div class="text-end text-muted mt-2"><small>共 ${data.total_errors} 条错误，显示最近 ${data.errors.length} 条</small></div>`;
            }
            document.getElementById('processingErrorsChart').innerHTML = errorHtml;
        }

        function showError(message) {
            const alertDiv = document.createElement('div');
            alertDiv.className = 'alert alert-danger alert-dismissible fade show';
            alertDiv.innerHTML = `
                <strong>错误!</strong> ${message}
                <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
            `;
            document.querySelector('.container-fluid').insertBefore(alertDiv, document.querySelector('.container-fluid').firstChild);

            setTimeout(() => {
                alertDiv.remove();
            }, 5000);
        }
    </script>
</body>
</html>
